package com.tistory.wonsama.db;

import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import com.tistory.wonsama.util.WFile;
import com.tistory.wonsama.util.WString;

/**
 * 오라클 VO 생성유틸
 * @author wonsama
 * @since 2011.12.28
 */
public class WOracleVoMaker {

	private static final int TYPE_ETC = -1;
	private static final int TYPE_STRING = 0;
	private static final int TYPE_INT = 1;

	private static final String MSG_ERR_MUST = "필수값이 누락 되었습니다.";
	private static final String MSG_ERR_LENGTH = "입력 길이가 초과 되었습니다.";
	private static final String MSG_ERR_NUMBER = "숫자만 입력 가능합니다.";

	/**
	 * 테이블 정보를 기준으로 VO를 생성한다 
	 * @param filePath 파일 경로 
	 * @param tableName 테이블 명 
	 * @param useValidator 유효성 검증 메소드 추가 여부
	 * @throws Exception 오류
	 * @since 2011.12.28
	 */
	public static void make( String filePath, String tableName) throws Exception
	{
		String _setParams = tableName + "," + tableName;
		String _getResult = "COLUMN_NAME, DATA_TYPE, DATA_DEFAULT, DATA_LENGTH, NULLABLE, COMMENTS";
		List<String> setParams = WString.splitToListWithTrim( _setParams , "," );
		List<String> getResult = WString.splitToListWithTrim( _getResult , "," );

		//SEARCH 
		//		WQueryHelper.printQueryResult( getQueryTableInfo() , setParams, getResult);
		List<HashMap<String, String>> result = WQueryHelper.selectDefault( getQueryTableInfo() , setParams, getResult);

		//MAKE : SENTENCE
		StringBuffer sb = new StringBuffer();
		String header = "public class "+tableName+" {\n\n";
		String tail = "\n}";

		sb.append(header);

		//VARIABLES
		Iterator<HashMap<String, String>> lineV = result.iterator();
		while(lineV.hasNext()){
			sb.append( makeLine( lineV.next() ) );
		}

		sb.append("\n");

		//GETTER, SETTER
		Iterator<HashMap<String, String>> lineGS = result.iterator();
		while(lineGS.hasNext()){
			sb.append( makeGS( lineGS.next() ) );
		}

		sb.append(tail);

		//WRITE FILE
		WFile.writeFile(filePath + tableName + ".java", sb.toString() );
	}


	/**
	 * 유효성 검증 메소드를 만든다
	 * @param line 라인정보
	 * @return 결과
	 * @since 2011.12.28
	 */
	private static String makeValidator( List<HashMap<String, String>> result )
	{


		//__________________________________________________________________________________________
		//확장 유효성 검증
		//__________________________________________________________________________________________
		//
		//
		//1. 특정 값 입력 제한 
		//sbExp.append("{ isNew : matches('[nNyY]', ?) is true:  '"N또는 Y만 입력 가능합니다."'}");
		//
		//2. 범위 입력 제한
		//sbExp.append("{ sal : ? > 5000 : '최소 연봉은 5000 이상입니다.' }");
		//
		//3. 날짜 형식 입력 제한 
		//sbExp.append("{srchEndCntrEndDate: matches('[0-9]{4}-[0-9]{2}-[0-9]{2}', ?) is true:  '날짜형식이 잘못되었습니다.'}");
		//
		//4. 숫자/영문/입력길이 제한 
		//sbExp.append("{srvyCoCode : matches('[0-9A-Z]{6}', ?) is true: '조사업체코드가 유효하지 않습니다.'}");

		StringBuffer sb = new StringBuffer();

		//COMMENT ___________________________________________________________
		sb.append("\t/**\n");
		sb.append("\t * <pre>\n");
		sb.append("\t * 유효성 검증 메시지\n");
		sb.append("\t * 탭 들어간 부분은 NULL 허용 필드임\n");
		sb.append("\t * </pre>\n");
		sb.append("\t * @return Validator Messages");
		sb.append("\n\t */\n");

		//FUNCTION ___________________________________________________________
		sb.append("\tpublic String toValidator(){\n\n");
		sb.append("\t\tStringBuffer sb = new StringBuffer();\n\n");

		Iterator<HashMap<String, String>> lineV = result.iterator();
		while(lineV.hasNext()){

			HashMap<String, String> line = lineV.next();

			String columnName = line.get("COLUMN_NAME");
			String dataType = line.get("DATA_TYPE");
			String dataLength = line.get("DATA_LENGTH");
			//			String dataDefault = line.get("DATA_DEFAULT");
			String nullable = line.get("NULLABLE");
			//			String comments = line.get("COMMENTS");

			String columnNameR = WString.underToCamelCase(columnName);
			int dataLengthR = Integer.parseInt( WString.NVL( dataLength , "0" ) );

			//NOT NULL
			if( nullable.equalsIgnoreCase("N") ){
				sb.append("\t\tsb.append(\"{ "+columnNameR+" : ? is not blank : '"+ MSG_ERR_MUST +"' }\");\n");
			}
			//LENGTH
			if( dataLengthR > 0 ){

				if( nullable.equalsIgnoreCase("Y") ){
					//					sb.append("\t\tif( "+columnNameR+"!=null && !"+columnNameR+".equals(\"\") )");
					sb.append("\t\t");
				}

				sb.append("\t\tsb.append(\"{ "+columnNameR+" : length(?) <= " + dataLengthR + " : '"+ MSG_ERR_LENGTH +"' }\");\n");
			}
			//FILED TYPE : INT ONLY
			if( dataType.equalsIgnoreCase("NUMBER") ){
				sb.append("\t\tsb.append(\"{ "+columnNameR+" : matches('^[0-9]*$', ?) is true:  '"+ MSG_ERR_NUMBER +"' }\");\n");
			}
		}

		sb.append("\n\t\treturn sb.toString();\n");
		sb.append("\t}\n\n");

		return sb.toString();
	}	

	/**
	 * StringMaker : GETTER SETTER
	 * @param line 라인정보
	 * @return 결과
	 * @since 2011.12.28
	 */
	private static String makeGS( HashMap<String, String> line)
	{
		String columnName = line.get("COLUMN_NAME");
		String dataType = line.get("DATA_TYPE");
		String dataLength = line.get("DATA_LENGTH");
		//		String dataDefault = line.get("DATA_DEFAULT");
		String nullable = line.get("NULLABLE");
		String comments = line.get("COMMENTS");

		StringBuffer sb = new StringBuffer();

		//GETTER - COMMENT ___________________________________________________________
		sb.append("\t/**\n");
		sb.append("\t * ");
		sb.append( "@return COMMENTS : " + comments );
		sb.append( ", LEN : " + dataLength );
		sb.append( ", NULL : " + nullable );
		sb.append("\n\t */\n");

		//GETTER - FUNCTION ___________________________________________________________
		sb.append("\t");
		int type = getType(dataType);
		switch(type){
		case TYPE_STRING:
			sb.append("public String get");
			break;
		case TYPE_INT:
			sb.append("public int get");
			break;
		default:
			sb.append("public Object gets");
			break;
		}
		sb.append(WString.toCapital(WString.underToCamelCase(columnName),true) + "() {");sb.append("\n");
		sb.append("\t\t");sb.append("return " + WString.underToCamelCase(columnName) + ";");sb.append("\n");
		sb.append("\t");sb.append("}\n\n");

		//GETTER - COMMENT ___________________________________________________________
		sb.append("\t/**\n");
		sb.append("\t * ");
		sb.append( "@param ");
		sb.append(WString.underToCamelCase(columnName));
		sb.append( " " + comments );
		sb.append( ", LEN : " + dataLength );
		sb.append( ", NULL : " + nullable );
		sb.append("\n\t */\n");

		//GETTER - FUNCTION ___________________________________________________________
		sb.append("\tpublic void set");
		sb.append(WString.toCapital(WString.underToCamelCase(columnName),true));
		switch(type){
		case TYPE_STRING:
			sb.append("(String ");
			break;
		case TYPE_INT:
			sb.append("(int ");
			break;
		default:
			sb.append("(Object ");
			break;
		}
		sb.append(WString.underToCamelCase(columnName));
		sb.append(") {\n");
		sb.append("\t\tthis.");
		sb.append(WString.underToCamelCase(columnName));
		sb.append(" = ");
		sb.append(WString.underToCamelCase(columnName));
		sb.append(";\n");
		sb.append("\t}\n\n");

		return sb.toString();
	}

	/**
	 * StringMaker : 
	 * @param line 
	 * @return 라인
	 * @since 2011.12.28
	 */
	private static String makeLine( HashMap<String, String> line)
	{
		String columnName = line.get("COLUMN_NAME");
		String dataType = line.get("DATA_TYPE");
		String dataLength = line.get("DATA_LENGTH");
		String dataDefault = line.get("DATA_DEFAULT");
		String nullable = line.get("NULLABLE");
		String comments = line.get("COMMENTS");

		StringBuffer sb = new StringBuffer();

		sb.append("\t");
		sb.append("private ");

		int type = getType(dataType);
		switch(type){
		case TYPE_STRING:
			sb.append("String ");
			break;
		case TYPE_INT:
			sb.append("int ");
			break;
		default:
			sb.append("Object ");
			break;
		}

		sb.append( WString.underToCamelCase( columnName ) );

		if(WString.NVL(dataDefault, "").trim().equals("")){ 
			sb.append( ";" );
		}else{

			dataDefault = dataDefault.replaceAll("\"", "");
			dataDefault = dataDefault.replaceAll("\'", "");

			switch(type){
			case TYPE_INT:
				sb.append( " = " + dataDefault + " ;");
				break;
			case TYPE_STRING:
				sb.append( " = \"" + dataDefault + "\" ;");
				break;
			}
		}

		sb.append("\t\t\t//");
		sb.append( "COMMENTS : " + comments );
		sb.append( ", LEN : " + dataLength );
		sb.append( ", NULL : " + nullable );

		sb.append("\n");


		return sb.toString();
	}


	/**
	 * 타입 정보를 알려준다
	 * @param dataType
	 * @return 타입
	 * @since 2011.12.28
	 */
	private static int getType(String dataType){

		if(dataType.indexOf("CHAR")>=0){
			return TYPE_STRING;
		}
		//차후 큰 수는 long, BigDecimal 등으로 치환하는 것은 dataLength 를 활용하여 구하도록 한다
		else if(dataType.indexOf("NUMBER")>=0){
			return TYPE_INT;
		}
		//기타 BLOB, CLOB 등은 나중에 생각하여 추가하도록 한다
		return TYPE_ETC;
	}



	/**
	 * 테이블 정보 조회 쿼리
	 * @return 쿼리
	 * @since 2011.12.28
	 */
	private static String getQueryTableInfo()
	{
		StringBuffer strSQL = new StringBuffer();
		strSQL.append("SELECT T.*, CC.COMMENTS ");
		strSQL.append("FROM ");
		strSQL.append("( ");
		strSQL.append("    SELECT ");
		strSQL.append("        COLUMN_NAME, DATA_TYPE, DATA_DEFAULT, DATA_LENGTH, NULLABLE ");
		strSQL.append("    FROM ");
		strSQL.append("        USER_TAB_COLUMNS ");
		strSQL.append("    WHERE ");
		strSQL.append("        TABLE_NAME = ? ");
		strSQL.append("    ORDER BY ");
		strSQL.append("        COLUMN_ID ");
		strSQL.append(") T ");
		strSQL.append("LEFT OUTER JOIN USER_COL_COMMENTS CC ON 1=1 ");
		strSQL.append("    AND CC.TABLE_NAME = ? ");
		strSQL.append("    AND T.COLUMN_NAME = CC.COLUMN_NAME ");

		return strSQL.toString();
	}

}
